import numpy as np
import pandas as pd


# def createData(filename):
#     fr = open(filename)
#     datamatLenth = len(fr.readlines()) - 1
#     datamat = []
#     lablemat = []
#     for line in fr.readlines():
#         linArr = []
#         for i in range(datamatLenth):
#             linArr.append(line[i])
#         datamat.append(linArr)
#         lablemat.append(line[-1])
#     return datamat, lablemat

def createData(filename):
    df = pd.read_csv(filename, header=0)
    datamat = []
    lablemat = []
    for i in range(int(len(df))):
        arrLine = []
        arrLine.append(1)
        arrLine.append(df['YearsExperience'][i])
        datamat.append(arrLine)
        lablemat.append(df['Salary'][i])
    return datamat, lablemat


# w=(x^T*x)^-1*x^T*y
# x=[             x^t=[x1,x2,x3......]
#     x1
#     x2
#     x3
#     x4
#     .
#     .
#    ]
# 最小二乘法:x^2=x^t*x=x1*x1+x2*x2+x3*x3+.......
# 求和(y-xi^t*w)^2
# (y-xi^t*w)^2=(y-xi^t*w)^t*(y-xi^t*w)
# 假设x*w=y
# x^t*x*w=x^t*y
# w=(x^t*x)^-1*x^t*y
# 一次训练完所有参数，有特定条件：因为要求逆矩阵，所以行列式不为0
# 主要计算量在求逆矩阵上
# 也可以用逻辑回归的每次训练的一点weight的方式来进行
def standRegres(datamat, lablemat):
    datamat1 = np.mat(datamat)
    lablemat1 = np.mat(lablemat)
    datamat2 = np.linalg.inv(datamat1.T * datamat1)
    ws = datamat2 * datamat1.T * lablemat1.T
    return ws


# w=(x^T*w*x)^-1*x^T*W*y 局部加权线性回归
# 高斯核：w(i,i)=exp(abs(x^-x)/2k^2)
def standGaussRegres(testpoint, datamat, lablemat, k=0.1):
    datamat1 = np.mat(datamat)
    lablemat1 = np.mat(lablemat)
    datamat1num = np.shape(datamat1)[0]
    # weight = np.mat(np.eye(datamat1num))
    weight = np.zeros((datamat1num, datamat1num))
    for i in range(datamat1num):
        datamat2 = testpoint - datamat1[i]
        weight[i][i] = np.exp((datamat2 * datamat2.T) / (-2 * k ** 2))
    datamat2 = np.linalg.inv(datamat1.T * weight * datamat1)
    ws = datamat2 * datamat1.T * weight * lablemat1.T
    return ws


import matplotlib.pyplot as plt


def drawPict(datamat, lablemat, ws, Localy1, Localy2, Localy3):
    datamat1 = np.mat(datamat)
    datamat2 = datamat1[:, 1:2]
    lablemat1 = np.mat(lablemat).T
    predictmat = datamat1 * ws

    # plt.xlabel('YearsExperience')
    # plt.ylabel('Salary')
    # # red dashes, blue squares and green triangles
    # plt.plot(datamat2, lablemat1, 'bs', c='red', label="12")
    # plt.plot(datamat2, predictmat, 'r', c='blue', label="预测值")
    # plt.plot(datamat2, Localy1, 'r', c='green', label="预测值")
    # plt.plot(datamat2, Localy2, 'r', c='yellow', label="预测值")
    # plt.plot(datamat2, Localy3, 'r', c='gray', label="预测值")
    # plt.legend(['实际值', '线性回归预测值', '局部加权线性回归预测值，k=0.1', '局部加权线性回归预测值，k=1', '局部加权线性回归预测值，k=0.01'])
    # plt.rcParams['font.sans-serif'] = ['SimHei']
    # plt.rcParams['axes.unicode_minus'] = False

    plt.figure(1)
    # 第一行第一列图形
    ax1 = plt.subplot(221)
    # 第一行第二列图形
    ax2 = plt.subplot(222)
    # # 第二行
    ax3 = plt.subplot(223)
    #
    ax4 = plt.subplot(224)
    # 选择ax1
    plt.sca(ax1)
    # 绘制红色曲线
    plt.plot(datamat2, lablemat1, 'bs', c='red')
    plt.plot(datamat2, predictmat, 'r', c='blue')
    # 选择ax2
    plt.sca(ax3)
    # # 绘制蓝色曲线
    plt.plot(datamat2, lablemat1, 'bs', c='red')
    plt.plot(datamat2, Localy1, 'r', c='green')
    # # 选择ax3
    plt.sca(ax2)
    plt.plot(datamat2, lablemat1, 'bs', c='red')
    plt.plot(datamat2, Localy2, 'r', c='yellow')
    #
    plt.sca(ax4)
    plt.plot(datamat2, lablemat1, 'bs', c='red')
    plt.plot(datamat2, Localy3, 'r', c='gray')
    plt.show()


if __name__ == '__main__':
    filename = 'C:/code/database/Salary_Data.csv'
    datamat, lablemat = createData(filename)
    ws = standRegres(datamat, lablemat)
    datamat1 = np.mat(datamat)
    lablemat1 = np.mat(lablemat)
    # print(np.mat(np.eye((3))))
    # np.corrcoef((datamat1 * ws).T, lablemat1)  相关系数：0.97824162
    datamat1num = np.shape(datamat1)[0]
    ypredict1 = np.zeros((datamat1num, 1))
    for i in range(datamat1num):
        ws1 = standGaussRegres(datamat1[i], datamat, lablemat)
        ypredict1[i] = datamat1[i] * ws1
    ypredict2 = np.zeros((datamat1num, 1))
    for i in range(datamat1num):
        ws2 = standGaussRegres(datamat1[i], datamat, lablemat, k=1)
        ypredict2[i] = datamat1[i] * ws2
    ypredict3 = np.zeros((datamat1num, 1))
    for i in range(datamat1num):
        ws3 = standGaussRegres(datamat1[i], datamat, lablemat, k=0.05)
        ypredict3[i] = datamat1[i] * ws3
    drawPict(datamat, lablemat, ws, ypredict1, ypredict2, ypredict3)
